public static void save(File fSource, File fDest, AnalysisConsumer acAnalysisResults)
      throws IOException {
    Reader r = new FileReader(fSource);
    IndentAwareWriter iaw =
        new IndentAwareWriter(new OutputStreamWriter(new FileOutputStream(fDest)));

    try {
      new Injector(r, iaw, new FileSaveConsumer(iaw, acAnalysisResults)).parseFile();
      iaw.flush();
      iaw.close();
    } catch (InjectorParseException ipe) {
      ipe.printStackTrace();
    }
  }
  public void onAttributeHeader(JavaAttribute ja) throws java.io.IOException {
    if (!m_fWroteDocComment) {
      // Feature without comment
      if ((m_iFeatures.hasNext())
          && (getCurrentFeature().getCommentID()
              == m_cComments
                  + 1)) { // ' + 1 ' because the number in m_cComments refers to the last doccomment
                          // that was actually written
        // Might need element-type/key-type spec (i.e., if it is a collection or map)
        if (ja.getType() != null) {
          try {
            Class clClass = ja.getFile().findType(ja.getType());

            if (clClass != null) {
              // Not a simple type --> check whether collection or map
              if (java.util.Collection.class.isAssignableFrom(clClass)
                  || java.util.Map.class.isAssignableFrom(clClass)) {
                // Yup! So we have to generate a comment for it!
                if (m_iawOutput != null) {
                  int nIndent = m_iawOutput.getCurrentIndent();

                  getCurrentFeature().indentComment(nIndent);

                  String sDocComment = getCurrentFeature().getDocComment();

                  if (sDocComment != null) {
                    m_iawOutput.write(sDocComment + "\n");

                    for (; nIndent > 0; nIndent--) {
                      m_iawOutput.write(" ");
                    }
                  }
                }

                m_adCurrentFeature = null; // Mark feature as handled...
                m_cComments++;
              }
            }
          } catch (InjectorParseException ipe) {
            System.err.println("Exception while saving attribute:");
            ipe.printStackTrace();

            throw new IOException(ipe.getMessage());
          }
        }
      }
    }
  }
  /**
   * Encountered a java documentation comment. Is called for comments on class level only, i.e.
   * inside a class, but outside of methods and attributes.
   *
   * @return if false is returned, the next class feature is ignored.
   */
  public boolean onDocComment(String doccomment) throws java.io.IOException {
    m_cComments++;

    if (m_iawOutput != null) {
      if ((m_iFeatures.hasNext()) && (getCurrentFeature().getCommentID() == m_cComments)) {
        m_iawOutput.write(getCurrentFeature().getDocComment(/*m_iawOutput.getCurrentIndent()*/ ));
        m_adCurrentFeature = null; // Mark feature as handled...
      } else {
        m_iawOutput.write(doccomment);
      }
    }

    m_fWroteDocComment = true;

    return true;
  }
  public void onFileDocComment(String doccomment) throws java.io.IOException {

    m_iawOutput.write(doccomment);
  }
 /**
  * Encountered the header of a java method. Is called additionally to {@link
  * #onClassFeature(JavaFeature, String)}.
  *
  * @parameter cf contains all parsed information about the method
  */
 public void onBehaviourHeader(JavaBehaviour jb) throws java.io.IOException {
   if (m_iawOutput != null) {
     m_iawOutput.write(jb.getLiteral());
   }
 }