JavaParser - save modified source code file with new name

261 Views Asked by At

I'm using JavaParser to modify java source code. My goal is to read a single java source code file (ArithmeticClassToBeMutated) and store it in a compilation unit. Then, i'd like to replace/mutate its arithmetic operators (PLUS,MINUS,MULTIPLY,DIVISION,REMAINDER). All instances of an operator (e.g. plus) shall always be replaced with another one (e.g. minus). In the end, i want to have 4 output files:

One java source code file where every "Plus" became a "Minus", one file where every "Plus" became a "Multiply", one file where every "Plus" became a "Division", and one file where every "Plus" became a "Remainder/Modulo). I can't type the symbols or else i get a formatting error.

In my code (see below), the replacement/modification itself works. Now, my question is: how can I change the name of the output source code files? I did it with the methods add and saveAll:

sourceRoot.add("", OperatorToBeMutated.name() + "_TO_" + arithmeticOperators[i].name() + "_MUTATED_"
                        + cu.getStorage().get().getFileName(), cu);
    
sourceRoot.saveAll(
                    CodeGenerationUtils.mavenModuleRoot(ReplacementAO.class).resolve(Paths.get("output")));

However, this creates two output files for each operator replacement. One file has the same name as the input file, and one file has my naming convention. The content is the same. What can I do to only save a single file (with my own naming) for each loop? Specifying no name would result in the output file overwriting itself with each iteration, as the name stays the same.
Thank you!

public static String filename = "ArithmeticClassToBeMutated.java";

    public static void main(String[] args) {

        for (i = 0; i < arithmeticOperators.length; i++) {

            if (arithmeticOperators[i] == OperatorToBeMutated) {
                continue;
            }

            sourceRoot = new SourceRoot(
                    CodeGenerationUtils.mavenModuleRoot(ReplacementAO.class).resolve("src/main/resources"));

            CompilationUnit cu = sourceRoot.parse("", filename);
            cu.accept(new ModifierVisitor<Void>() {

                @Override
                public Visitable visit(BinaryExpr n, Void arg) {

                    if (n.getOperator() == OperatorToBeMutated && n.getLeft().isNameExpr()
                            && n.getRight().isNameExpr()) {
                        n.setOperator(arithmeticOperators[i]);
                        comment.setContent("Here, the operator " + OperatorToBeMutated.name()
                                + " was mutated with the operator " + arithmeticOperators[i].name() + ".");
                        n.setComment(comment);
                    }
                    return super.visit(n, arg);
                }
            }, null);

            sourceRoot.add("", OperatorToBeMutated.name() + "_TO_" + arithmeticOperators[i].name() + "_MUTATED_"
                    + cu.getStorage().get().getFileName(), cu);

            sourceRoot.saveAll(
                    CodeGenerationUtils.mavenModuleRoot(ReplacementAO.class).resolve(Paths.get("output")));
        }
    }
1

There are 1 best solutions below

0
On

You wouldn't want to rename your file name to be different from the class name, as a public java class needs to have the same name as its file name. As far as I am aware this will throw a compiler error for public classes:

Can I compile a java file with a different name than the class?

I would suggest putting the mutated classes into different folders. Just adding another directory at the end of your path will automatically create a new folder. So for your example:

sourceRoot.saveAll(CodeGenerationUtils.mavenModuleRoot(LogicalOperators.class).resolve(Paths.get("output" + "/mutation1")));