现在我们的需求是对java代码进行转换:
转换前的java方法是:
public XYDataItem addOrUpdate(Number x, Number y) {
if (x == null) {
throw new IllegalArgumentException("Null 'x' argument.");
}
XYDataItem overwritten = null;
int index = indexOf(x);
if (index >= 0 && !this.allowDuplicateXValues) {
XYDataItem existing = (XYDataItem) this.data.get(index);
try {
overwritten = (XYDataItem) existing.clone();
} catch (CloneNotSupportedException e) {
throw new SeriesException("Couldn't clone XYDataItem!");
}
existing.setY(y);
} else {
if (this.autoSort) {
this.data.add(-index - 1, new XYDataItem(x, y));
} else {
this.data.add(new XYDataItem(x, y));
}
if (getItemCount() > this.maximumItemCount) {
this.data.remove(0);
}
}
fireSeriesChanged();
return overwritten;
}
要求转换后的是:
public XYDataItem addOrUpdate(Number x, Number y) {
if (x != null) {
throw new IllegalArgumentException("Null 'x' argument.");
}
XYDataItem overwritten = null;
int index = indexOf(x);
if ((index <= 0) || (!this.allowDuplicateXValues)) {
XYDataItem existing = ((XYDataItem) (this.data.get(index)));
try {
overwritten = ((XYDataItem) (existing.clone()));
} catch (CloneNotSupportedException e) {
throw new SeriesException("Couldn't clone XYDataItem!");
}
existing.setY(y);
} else {
if (this.autoSort) {
this.data.add((-index) - 1, new XYDataItem(x, y));
} else {
this.data.add(new XYDataItem(x, y));
}
if (getItemCount() < this.maximumItemCount) {
this.data.remove(0);
}
}
fireSeriesChanged();
return overwritten;
}
可以对比看到, 一些if里面的判断条件变了, 取反了.
spoon是用于分析、重写、转换、传输java源代码, 非常的强大....
下面是我们的代码,
1.设定依赖
<dependencies>
<dependency>
<groupId>fr.inria.gforge.spoon</groupId>
<artifactId>spoon-core</artifactId>
<version>8.3.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.6.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.6.2</version>
</dependency>
</dependencies>
2.写核心的转换方法:
package com.onyx;
import spoon.Launcher;
import spoon.reflect.code.BinaryOperatorKind;
import spoon.reflect.code.CtBlock;
import spoon.reflect.code.CtExpression;
import spoon.reflect.code.CtStatement;
import spoon.reflect.declaration.CtClass;
import spoon.support.reflect.code.CtBinaryOperatorImpl;
import spoon.support.reflect.code.CtBlockImpl;
import spoon.support.reflect.code.CtIfImpl;
import spoon.support.reflect.declaration.CtMethodImpl;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static spoon.reflect.code.BinaryOperatorKind.*;
public class JavaCodeTransform {
/**
* get origin and target method string
*
* @return
* @throws Exception
*/
public static Map<String, String> getOriginAndTargetMethod(String path) throws Exception {
CtClass ctClass = Launcher.parseClass(getJavaCode(path));
//get all method
Set<CtMethodImpl> allMethods = ctClass.getAllMethods();
Map<String, String> map = new HashMap<String, String>(2);
//scan all method
for (CtMethodImpl method : allMethods) {
String simpleName = method.getSimpleName();
//only handle addOrUpdate method
if (!"addOrUpdate".equals(simpleName)) {
continue;
}
//map.put("origin", method.toString());
System.out.println("the origin method is :" + method.toString());
//get this method body content
CtBlock body = method.getBody();
List<CtStatement> statements = body.getStatements();
for (CtStatement statement : statements) {
if (!(statement instanceof CtIfImpl)) {
continue;
}
CtIfImpl ctIf = (CtIfImpl) statement;
CtBinaryOperatorImpl<Boolean> condition = (CtBinaryOperatorImpl) ctIf.getCondition();
CtExpression<?> handOperand = condition.getLeftHandOperand();
if (handOperand instanceof CtBinaryOperatorImpl) {
CtBinaryOperatorImpl<Boolean> leftHandOperand = (CtBinaryOperatorImpl<Boolean>) handOperand;
BinaryOperatorKind symbol = getOppositeSymbol(leftHandOperand.getKind());
leftHandOperand.setKind(symbol);
}
//else condition
CtBlockImpl elseStatement = ctIf.getElseStatement();
if (elseStatement != null) {
List<CtIfImpl> ctIfs = elseStatement.getStatements();
if (ctIfs != null && ctIfs.size() > 0) {
for (CtIfImpl anIf : ctIfs) {
replaceCondition(anIf);
}
}
}
replaceCondition(ctIf);
}
map.put("target", method.toString());
System.out.println("the target method is :" + method.toString());
}
return map;
}
/**
* reserve the if condition
*/
private static void replaceCondition(CtIfImpl ctIf) {
if (ctIf == null) {
return;
}
CtExpression<Boolean> ifCondition = ctIf.getCondition();
if (ifCondition instanceof CtBinaryOperatorImpl) {
CtBinaryOperatorImpl<Boolean> binaryOperator = (CtBinaryOperatorImpl<Boolean>) ifCondition;
BinaryOperatorKind kind = binaryOperator.getKind();
BinaryOperatorKind symbol = getOppositeSymbol(kind);
binaryOperator.setKind(symbol);
ctIf.setCondition(binaryOperator);
}
}
/**
* get the operator kind
*
* @param kind
* @return
*/
private static BinaryOperatorKind getOppositeSymbol(BinaryOperatorKind kind) {
if (kind == null) {
return null;
}
switch (kind) {
case OR:
return AND;
case AND:
return OR;
case BITOR:
return BITAND;
case BITAND:
return BITOR;
case EQ:
return NE;
case NE:
return EQ;
case LT:
return GT;
case GT:
return LT;
case LE:
return GE;
case GE:
return LE;
}
return null;
}
/**
* get java method code string, into Demo class.
*
* @return
*/
private static String getJavaCode(String path) throws IOException {
File file = new File(path);
BufferedReader reader = new BufferedReader(new FileReader(file));
StringBuffer sb = new StringBuffer();
sb.append("public class Demo { ");
String tmp = null;
while ((tmp = reader.readLine()) != null) {
sb.append(tmp);
}
sb.append(" }");
return sb.toString();
}
}
3. 写测试方法
import com.onyx.JavaCodeTransform;
import org.junit.Assert;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.Map;
public class Test {
@org.junit.Test
public void test() throws Exception {
//put your source method file, i put D:\method.txt
Map<String, String> map = JavaCodeTransform.getOriginAndTargetMethod("D:\\method.txt");
String target = deleteAllBlank(map.get("target"));
//load your result method in file, i put D:\result.txt
String javaCode = deleteAllBlank(getJavaCode("D:\\result.txt"));
Assert.assertEquals(true, target.equals(javaCode));
}
/**
* delete all blocks
*
* @param s
* @return
*/
public String deleteAllBlank(String s) {
if (s == null) {
return s;
}
String replaceAll = s.replaceAll("\\s*", "");
return replaceAll;
}
/**
* get file content to string
*/
private String getJavaCode(String path) throws IOException {
BufferedReader reader = new BufferedReader(new FileReader(new File(path)));
StringBuffer sb = new StringBuffer();
String tmp = null;
while ((tmp = reader.readLine()) != null) {
sb.append(tmp);
}
return sb.toString();
}
}
就完成了.