private Document _getJavadocDocument(JavaClass javaClass) throws Exception {
    Element rootElement = _saxReaderUtil.createElement("javadoc");

    Document document = _saxReaderUtil.createDocument(rootElement);

    DocUtil.add(rootElement, "name", javaClass.getName());
    DocUtil.add(rootElement, "type", javaClass.getFullyQualifiedName());

    _addClassCommentElement(rootElement, javaClass);
    _addDocletElements(rootElement, javaClass, "author");
    _addDocletElements(rootElement, javaClass, "version");
    _addDocletElements(rootElement, javaClass, "see");
    _addDocletElements(rootElement, javaClass, "since");
    _addDocletElements(rootElement, javaClass, "serial");
    _addDocletElements(rootElement, javaClass, "deprecated");

    JavaMethod[] javaMethods = javaClass.getMethods();

    for (JavaMethod javaMethod : javaMethods) {
      _addMethodElement(rootElement, javaMethod);
    }

    JavaField[] javaFields = javaClass.getFields();

    for (JavaField javaField : javaFields) {
      _addFieldElement(rootElement, javaField);
    }

    return document;
  }
  @Test
  public void generateDotClassDiagram() throws IOException {
    JavaProjectBuilder javaProjectBuilder = new JavaProjectBuilder();
    javaProjectBuilder.addSourceTree(new File("./src/main/java/me/loki2302/"));

    StringBuilder stringBuilder = new StringBuilder();

    stringBuilder.append("digraph g { overlap = false; node [shape=rectangle;];\n");

    int clusterIdx = 0;
    for (JavaPackage javaPackage : javaProjectBuilder.getPackages()) {
      stringBuilder.append(String.format("subgraph cluster_%d {\n", clusterIdx++));
      stringBuilder.append(String.format("label=\"%s\";\n", javaPackage.getName()));
      for (JavaClass javaClass : javaPackage.getClasses()) {
        stringBuilder.append(String.format("%s;\n", simpleName(javaClass.getName())));
      }
      stringBuilder.append("}\n");
    }

    for (JavaClass javaClass : javaProjectBuilder.getClasses()) {
      // inheritance
      JavaClass superClass = javaClass.getSuperJavaClass();
      if (superClass != null) {
        if (!shouldIgnore(superClass)) {
          stringBuilder.append(
              String.format(
                  "%s -> %s;\n",
                  simpleName(javaClass.getName()), simpleName(superClass.getName())));
        }
      }

      for (JavaClass i : javaClass.getInterfaces()) {
        if (shouldIgnore(i)) {
          continue;
        }

        stringBuilder.append(
            String.format("%s -> %s;\n", simpleName(javaClass.getName()), simpleName(i.getName())));
      }

      // delegation
      List<JavaField> fields = javaClass.getFields();
      for (JavaField field : fields) {
        if (shouldIgnore(field.getType())) {
          continue;
        }

        stringBuilder.append(
            String.format(
                "%s -> %s;\n",
                simpleName(javaClass.getName()), simpleName(field.getType().getName())));
      }
    }

    stringBuilder.append("}\n");

    documentation.text("classDiagram", stringBuilder.toString());
  }
  private void _addClassCommentElement(Element rootElement, JavaClass javaClass) {

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

    String comment = _getCDATA(javaClass);

    if (comment.startsWith("Copyright (c) 2000-2010 Liferay, Inc.")) {
      comment = StringPool.BLANK;
    }

    if (comment.startsWith("<a href=\"" + javaClass.getName() + ".java.html\">")) {

      int pos = comment.indexOf("</a>");

      comment = comment.substring(pos + 4).trim();
    }

    commentElement.addCDATA(comment);
  }
  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 _addThrowsElement(
      Element methodElement, Type exceptionType, DocletTag[] throwsDocletTags) {

    JavaClass javaClass = exceptionType.getJavaClass();

    String name = javaClass.getName();

    String value = null;

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

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

        break;
      }
    }

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

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

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

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

    value = _trimMultilineText(value);

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

    commentElement.addCDATA(_getCDATA(value));
  }
  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 void _updateJavaFromDocument(
      String fileName, String originalContent, String javadocLessContent, Document document)
      throws Exception {

    String[] lines = StringUtil.splitLines(javadocLessContent);

    JavaClass javaClass = _getJavaClass(fileName, new UnsyncStringReader(javadocLessContent));

    _updateLanguageProperties(document, javaClass.getName());

    List<Tuple> ancestorJavaClassTuples = new ArrayList<Tuple>();

    ancestorJavaClassTuples = _addAncestorJavaClassTuples(javaClass, ancestorJavaClassTuples);

    Element rootElement = document.getRootElement();

    Map<Integer, String> commentsMap = new TreeMap<Integer, String>();

    commentsMap.put(
        _getJavaClassLineNumber(javaClass), _getJavaClassComment(rootElement, javaClass));

    Map<String, Element> methodElementsMap = new HashMap<String, Element>();

    List<Element> methodElements = rootElement.elements("method");

    for (Element methodElement : methodElements) {
      String methodKey = _getMethodKey(methodElement);

      methodElementsMap.put(methodKey, methodElement);
    }

    JavaMethod[] javaMethods = javaClass.getMethods();

    for (JavaMethod javaMethod : javaMethods) {
      if (commentsMap.containsKey(javaMethod.getLineNumber())) {
        continue;
      }

      String javaMethodComment = _getJavaMethodComment(lines, methodElementsMap, javaMethod);

      // Handle override tag insertion

      if (!_hasAnnotation(javaMethod, "Override")) {
        if (_isOverrideMethod(javaClass, javaMethod, ancestorJavaClassTuples)) {

          String overrideLine = _getIndent(lines, javaMethod) + "@Override\n";

          if (Validator.isNotNull(javaMethodComment)) {
            javaMethodComment = javaMethodComment + overrideLine;
          } else {
            javaMethodComment = overrideLine;
          }
        }
      }

      commentsMap.put(javaMethod.getLineNumber(), javaMethodComment);
    }

    Map<String, Element> fieldElementsMap = new HashMap<String, Element>();

    List<Element> fieldElements = rootElement.elements("field");

    for (Element fieldElement : fieldElements) {
      String fieldKey = _getFieldKey(fieldElement);

      fieldElementsMap.put(fieldKey, fieldElement);
    }

    JavaField[] javaFields = javaClass.getFields();

    for (JavaField javaField : javaFields) {
      if (commentsMap.containsKey(javaField.getLineNumber())) {
        continue;
      }

      commentsMap.put(
          javaField.getLineNumber(), _getJavaFieldComment(lines, fieldElementsMap, javaField));
    }

    StringBundler sb = new StringBundler(javadocLessContent.length());

    for (int lineNumber = 1; lineNumber <= lines.length; lineNumber++) {
      String line = lines[lineNumber - 1];

      String comments = commentsMap.get(lineNumber);

      if (comments != null) {
        sb.append(comments);
      }

      sb.append(line);
      sb.append("\n");
    }

    String formattedContent = sb.toString().trim();

    if (!originalContent.equals(formattedContent)) {
      File file = new File(_inputDir + fileName);

      _fileUtil.write(file, formattedContent.getBytes(StringPool.UTF8));

      System.out.println("Writing " + file);
    }
  }
 public String getName() {
   return javaClass.getName();
 }