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
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.fc</groupId>
<artifactId>sysout-cleanup</artifactId>
<version>1.0</version>
<repositories>
<repository>
<id>javaparser</id>
<name>JavaParser Repository</name>
<url>http://javaparser.googlecode.com/svn/maven2</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<properties>
<commons-io-version>2.0.1</commons-io-version>
<java-parser-version>1.0.8</java-parser-version>
</properties>
<dependencies>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>${commons-io-version}</version>
</dependency>
<dependency>
<groupId>com.google.code.javaparser</groupId>
<artifactId>javaparser</artifactId>
<version>${java-parser-version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
view raw pom.xml hosted with ❤ by GitHub
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&lt;Object&gt; {
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>");
}
}
}

Luhn algorithm in elisp

I was looking for the checksum validation of credit card numbers and came across the Luhn Algorithm. I had emacs open and on a whim decided I'll try and implement it using elisp. I'm no lisp programmer but, have in the past managed to write some basic elisp in .emacs so, I guessed it would take me about .5hr at most.

I guessed wrong. It took me a lot longer to wrap my head around even some of the simple elisp constructs like let and lambda took quite a while and it took a lot longer than I anticipated. Here, I present to you the fruit of my labors :)
(defun luhn-sum (list n)
(if (null list)
0
(+ (let ((x (car list)))
(if (= 1 (mod n 2))
(let ((y (* 2 x)))
(if (> y 9)
(+ 1 (mod y 10))
y))
x))
(luhn-sum (cdr list) (+ 1 n)))
)
)
(defun card-no-str-to-num (card-no)
(mapcar (lambda (x) (string-to-number x 10)) (cdr (reverse (cdr (split-string card-no "")))))
)
(defun luhn-check (card-no)
(eq 0 (mod (luhn-sum (card-no-str-to-num card-no) 0) 10))
)
(luhn-check "49927398716")
view raw luhn-check.el hosted with ❤ by GitHub