Friday, October 07, 2011

Clean sysouts from java project

Recently I was working in a project that had a lot of sysouts (System.out.println) peppered all over the code. I tried the usual sed approach find . -name '*.java' | xargs sed -i '/System.out.println/d' and that din't work out too well because of multiline sysouts. So, I decided to try the AST approach using the java parser from http://code.google.com/p/javaparser/. So, create a maven project add the javaparser repository and dependency in the pom.xml as given below

  4.0.0

  org.fc
  sysout-cleanup
  1.0

  
    
      javaparser
      JavaParser Repository
      http://javaparser.googlecode.com/svn/maven2
      
        false
      
    
  

  
    2.0.1
    1.0.8
  

  
    
      commons-io
      commons-io
      ${commons-io-version}
    
    
      com.google.code.javaparser
      javaparser
      ${java-parser-version}
    
  
  
    
      
        maven-compiler-plugin
        
          1.6
          1.6
        
      
    
  
  
And the java code that creates the AST and looks for the System.out.println method call
package org.fc;

import japa.parser.JavaParser;
import japa.parser.ast.CompilationUnit;
import japa.parser.ast.expr.FieldAccessExpr;
import japa.parser.ast.expr.MethodCallExpr;
import japa.parser.ast.expr.NameExpr;
import japa.parser.ast.stmt.BlockStmt;
import japa.parser.ast.stmt.ExpressionStmt;
import japa.parser.ast.stmt.Statement;
import japa.parser.ast.visitor.VoidVisitorAdapter;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;


public class CleanupSysOut {
  File inputFile;
  File outputFile;
  Map<String, String> namespaceMap = new HashMap<String, String>();
  public CleanupSysOut(File file) {
    inputFile = file;
  }
  public CleanupSysOut(File in, File out) {
    inputFile = in;
    outputFile = out;
  }
  
  protected CompilationUnit getCompilationUnit() {
    CompilationUnit cu = null;
    InputStream in = null;
    try {
      in = new FileInputStream(inputFile);
      cu = JavaParser.parse(in);
    } catch (Exception e) {
      throw new RuntimeException(e);
    } finally {
      IOUtils.closeQuietly(in);
    }
    return cu;
  }
  
  protected void writeOutput(CompilationUnit cu) throws IOException {
    
    PrintStream out = new PrintStream(new FileOutputStream(outputFile));
    out.println(cu.toString());
    IOUtils.closeQuietly(out);
  }
  
  protected String debugPrint(CompilationUnit cu) throws IOException {
    return cu.toString();
  }
  
  // MethodVisitor
  private class MethodVisitor extends VoidVisitorAdapter<Object> {
    private boolean isSysout(MethodCallExpr methodCall) {
      if ( "println".equals(methodCall.getName()) ) {
        if ( methodCall.getScope() instanceof FieldAccessExpr ) {
          FieldAccessExpr fieldExpr = (FieldAccessExpr) methodCall.getScope();
          if ( "out".equals(fieldExpr.getField()) ) {
            if ( fieldExpr.getScope() instanceof NameExpr ) {
              NameExpr clazz = (NameExpr) fieldExpr.getScope();
              if ( "System".equals(clazz.getName()) ) {
                return true;
              }
            }
          }
        }
      }
      return false;
    }
    @Override
    public void visit(BlockStmt blockStmt, Object arg) {
      List<Statement> stmts = blockStmt.getStmts();
      if ( null != stmts ) {
        Iterator<Statement> itr = stmts.iterator();
        while ( itr.hasNext() ) {
          Statement stmt = itr.next();
          if ( stmt instanceof ExpressionStmt ) {
            if ( ((ExpressionStmt) stmt).getExpression() instanceof MethodCallExpr ) {
              MethodCallExpr methodCall = (MethodCallExpr) ((ExpressionStmt) stmt).getExpression();
              if ( isSysout(methodCall) ) {
                itr.remove();
              }
            }
          } else {
            stmt.accept(this, arg);
          }
        }
      }
    }
  }
  // MethodVisitor ends
  
  public void doCleanup() {
    try {
      CompilationUnit cu = getCompilationUnit();
      new MethodVisitor().visit(cu, null);
      if ( null != outputFile ) {
        writeOutput(cu);
      }
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }
  static void cleanupDir(File inputDir, File  outputDir) {
    for ( File java : FileUtils.listFiles(inputDir, new String[] { "java" }, true) ) {
      String relativePath = java.getAbsolutePath().replace(inputDir.getAbsolutePath(), "").substring(1);
      File outputFile = new File(outputDir, relativePath);
      outputFile.getParentFile().mkdirs();
      new CleanupSysOut(java, outputFile).doCleanup();
    }
  }
  public static void main(String[] args) {
    if ( args.length == 2 ) {
      cleanupDir(new File(args[0]), new File(args[1]));
    } else {
      System.err.println("Usage: java " + CleanupSysOut.class.getName() + " <input-dir> <output-dir>");
    }
  }
}

No comments: