[英]Editing/Modifying a .java file programmatically? (not the .class file)
所以,这是一段使用CodeModel生成 java 代码的代码:
JCodeModel cm = new JCodeModel();
JDefinedClass dc = cm._class("foo.Bar");
JMethod m = dc.method(0, int.class, "foo");
m.body()._return(JExpr.lit(5));
File f = new File("C:/target/classes");
f.mkdirs();
cm.build(f);
此代码生成一个 .java 文件:
package foo;
public class Bar {
int foo() {
return 5;
}
}
但是,我不希望 CodeModel 为我创建一个新的 java 文件。 我已经有一个 .java 文件,并且想向其中的方法添加几行代码。 所以,我希望 API 直接修改 java 文件/创建它的修改副本。 有没有办法做到这一点?
...我希望 API 直接修改 java 文件/创建它的修改副本。 有没有办法做到这一点?
JavaParser是一个 API,它允许您读入 Java 文件,修改它们,并以字符串的形式获取结果。
更具体地说,JavaParser 解析文件并构建一个 AST(抽象语法树)。 然后,您可以使用 API 修改表示源代码的 JavaParser AST,并检索 AST 的字符串表示。
我已经有一个 .java 文件,并且想向其中的方法添加几行代码。
下面是使用 JavaParser 在方法主体的末尾添加一行并打印结果的示例:
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.MethodDeclaration;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Optional;
public class Main {
public static void someMethod() {
// Lines will be added here.
}
public static void main( String[] args ) throws FileNotFoundException {
String newStatement = "System.out.println(\"Hello world!\");";
File myClassSourceFile = new File( "Main.java" );
JavaParser parser = new JavaParser();
ParseResult<CompilationUnit> pr = parser.parse( myClassSourceFile );
Optional<CompilationUnit> ocu = pr.getResult();
if( ocu.isPresent() ) {
CompilationUnit cu = ocu.get();
ClassOrInterfaceDeclaration decl = cu.getClassByName( "Main" ).get();
MethodDeclaration method = decl.getMethods().get( 0 );
method.getBody().ifPresent( ( b ) -> b.addStatement( newStatement ) );
}
// Print out the resulting Java source code.
System.out.println( pr.toString() );
}
}
CompilationUnit - 来自 JavaParser 的 javadoc,“此类代表整个编译单元。每个 java 文件表示一个编译单元。”
在您的代码中,用适当的处理替换Option.get()
调用。
将方法日志添加到命令行上给出的类名的示例:
public class Main {
public static void main( final String[] args ) throws FileNotFoundException {
final File sourceFile = new File( args[ 0 ] );
final JavaParser parser = new JavaParser();
final ParseResult<CompilationUnit> pr = parser.parse( sourceFile );
final Optional<CompilationUnit> ocu = pr.getResult();
if( ocu.isPresent() ) {
final CompilationUnit cu = ocu.get();
final List<TypeDeclaration<?>> types = cu.getTypes();
for( final TypeDeclaration<?> type : types ) {
final List<MethodDeclaration> methods = type.getMethods();
for( final MethodDeclaration method : methods ) {
final Optional<BlockStmt> body = method.getBody();
final String m = format( "%s::%s( %s )",
type.getNameAsString(),
method.getNameAsString(),
method.getParameters().toString() );
final String mBegan = format(
"System.out.println(\"BEGAN %s\");", m );
final String mEnded = format(
"System.out.println(\"ENDED %s\");", m );
final Statement sBegan = parseStatement( mBegan );
final Statement sEnded = parseStatement( mEnded );
body.ifPresent( ( b ) -> {
final int i = b.getStatements().size();
b.addStatement( 0, sBegan );
// Insert before any "return" statement.
b.addStatement( i, sEnded );
} );
}
System.out.println( cu.toString() );
}
}
}
}
这会将更改后的源文件写入标准输出。 如果将Main
文件放在core
项目的主包中,则可以构建core
项目的 JAR 文件(例如, mvn package
)。 将 JAR 文件重命名为javaparser.jar
,然后在所有 JAR 文件上运行Main
:
for i in $(find . -type f -name "*.java"); do \
java -cp javaparser.jar com.github.javaparser.Main "$i" > \
"$i.jp";
done
当然,让 Java 遍历目录树会更有效率。 一旦.jp
文件出现并且看起来没问题,您可以使用以下方法重命名它们:
find . -type f -name "*jp" -size +100c -exec \
sh -c 'mv {} $(dirname {})/$(basename {} .jp)' \;
这将破坏原始格式,使其相当不适合签入存储库。 某些 Java 14 语句可能无法转换为可以编译的文件。 天啊。
您确实需要对要修改的代码进行完整解析,以确保将代码插入到正确的位置。 我原以为最好的办法是使用允许重写代码的现有解析工具,而不是尝试手动执行某些操作。
Eclipse IDE 做这样的事情来支持代码重构。 这篇文章可能会有所帮助。
你想要的是一个程序转换系统。 这是一个解析源文件的工具,可以应用转换来修改它,并通过修改重新生成源代码。
源到源转换系统接受以下形式的规则:
lhs -> rhs if cond
其中lhs和rhs是语言有效片段的源模式, cond检查规则是否可以安全应用。 (考虑“?x/?x -> 1 if ?x~=0”;您需要条件来验证除法是否有效)。
我们的DMS 软件再造工具包就是这样一种工具。 DMS 拥有完整的 C、C++、C#、Java、COBOL、Python、PHP 和 ECMAScript 前端解析器(与许多鲜为人知的语言一样)并且可以直接应用这些规则。 DMS 还提供符号表构建以及控制和数据流分析,因为这些通常在定义复杂规则的条件时很有用。 如果需要,您还可以退回到“标准”程序界面来访问树节点和修改 AST。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.