当前位置: 首页 > 工具软件 > Spoon > 使用案例 >

使用spoon对java代码进行转换

蒋阳华
2023-12-01

现在我们的需求是对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();
    }


}

就完成了.

 类似资料: