Изменение значения переменной в Java-файле

158
14 февраля 2019, 14:20

Есть Java-файл. Допустим с именем Example.java и в нем, есть код:

public class EXAMPLE {
    public static void main(String[] args) {
        int x = 10;
        System.out.println(x);
    }
}

Как мне изменить значение x = 10 на x = 30 через другую Java-программу?

Как должна, в теории, произойти изменение(как я это вижу):

Другая java-программа (допустим, Example2.java) открывает файл EXAMPLE.java, считывает все строки и находит ту самую - x = 10. Далее эта строка удаляется и на месте нее появляется x = 10. Из-за того, что информация должна куда-то записываться во время такх изменений - она будет записываться в файл EXAMPLE_temp.java. После завершения процесса изменения переменной, EXAMPLE_temp.java переименовывается в EXAMPLE.java и генерируется новый EXAMPLE.class. Дальше, при компиляции новой версии файла EXAMPLE.java, в консоли должно протсто вывестись:

30

Почему это важно?
В нынешний момент, чтобы изменить ОДНО ЧИСЛО в файле, мне приходится держать отдельно *.txt документ, в который я произвожу изменение данных.

Почему я не пробовал сам "поэкспериментировать/почитать"? .
Потому что мне интересно узнать, что могут посоветовать знающие и прошаренные люди. Мне интересен разный подход к решению данной проблемы

(Простите за офф-топик, но без этого никак.)

Answer 1

Работа с исходным кодом как с текстом - путь недостойный самурая. Знающие и прошаренные люди советуют использовать API компилятора для разбора исходника в абстрактное синтаксическое дерево (AST), модификацию этого дерева и его компиляцию всё тем же API компилятора.

Example.java

public class Example {
    public static void main(String[] args) {
        int x = 10;
        System.out.println(x);
    }
}

JavaSourceFromString.java

import java.net.URI;
import javax.tools.SimpleJavaFileObject;

/**
 * Класс эмулирующий для компилятора файлы исходного кода
 * и позволяющий компилировать код прямо из памяти
 */    
class JavaSourceFromString extends SimpleJavaFileObject {
    private final String code;
    public JavaSourceFromString(String name, String code) {
        super(URI.create("string:///" + name.replace('.','/') + Kind.SOURCE.extension), Kind.SOURCE);
        this.code = code;
    }
    @Override
    public CharSequence getCharContent(boolean ignoreEncodingErrors) {
        return code;
    }
}

Translator.java

import com.sun.source.util.JavacTask;
import com.sun.tools.javac.api.BasicJavacTask;
import com.sun.tools.javac.model.JavacElements;
import com.sun.tools.javac.tree.TreeMaker;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.TreeTranslator;
import com.sun.tools.javac.util.Context;

// Класс обхода и модификации AST
public class Translator extends TreeTranslator {
    private final TreeMaker treeMaker;
    private final JavacElements elements;
    public Translator(JavacTask task) {
        Context context = ((BasicJavacTask) task).getContext();
        treeMaker = TreeMaker.instance(context);
        elements = JavacElements.instance(context);
    }
    // Встречено определение переменной    
    @Override
    public void visitVarDef(JCTree.JCVariableDecl tree) {
        String varName = tree.getName().toString();
        if ("x".equals(varName)) {  // Переменная имеет имя "x"
            // Подменяем определение, заменяя литерал
            result = treeMaker.VarDef(tree.getModifiers(), tree.getName(), tree.vartype, treeMaker.Literal(30));
        }
        else {
            super.visitVarDef(tree);
        }
    }
}

Parser.java

import java.util.List;
import java.util.ArrayList;
import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.util.JavacTask;
import com.sun.tools.javac.tree.JCTree;

public class Parser {
    public static void main(String[] args) throws Exception {
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
        // Считываем исходный файл
        Iterable<? extends JavaFileObject> fileObjects = fileManager.getJavaFileObjects("Example.java");
        JavacTask javac = (JavacTask) compiler.getTask(null, fileManager, null, null, null, fileObjects);
        Translator translator = new Translator(javac);
        List<JavaFileObject> sources = new ArrayList<>();
        // Парсим исходный файл в деревья
        for (CompilationUnitTree tree : javac.parse()) {
            // Модифицируем деревья
            ((JCTree.JCCompilationUnit) tree).accept(translator);
            // Сохраняем результат в память
            sources.add(new JavaSourceFromString("Example", tree.toString()));
        }
        // Компилируем
        CompilationTask task = compiler.getTask(null, null, null, null, null, sources);
        task.call();
    }
}
READ ALSO
Шаринг по сайту

Шаринг по сайту

К примеру есть некий сайтУ сайта есть пользователи

177
PropertyGrid в ExtJs

PropertyGrid в ExtJs

У меня есть store со значениями, где хранятся типы данных и их обозначения с id и тд

167