Şu satırı dahil ederiz
import com.sun.source.util.Plugin;
java compiler tarafından çağrılır ve kod üretebilmeyi sağlar. java compiler javac komutu veya JavaCompiler arayüzü olabilirMaven
Şu satırı dahil ederiz
<dependency>
<groupId>com.sun</groupId>
<scope>system</scope>
<artifactId>tools</artifactId>
<version>1.8.0</version>
<systemPath>${java.home}/../lib/tools.jar</systemPath>
</dependency>
init metoduÖrnek
Şöyle yaparız
public class myJavacPlugin implements Plugin {
@Override
public String getName() {
return "InterviewBit";
}
@Override
public void init(JavacTask task, String... args) {
Context context = ((BasicJavacTask) task).getContext();
Log.instance(context)
.printRawLines(Log.WriterKind.NOTICE, "Hi from " + getName());
}
}
Şu dosyayı yaratırız
META-INF/services/com.sun.source.utility.Plugin
Dosyanın içi şöyledir
com.JavaTutorials.javac.myJavacPlugin
Çalıştırmak için şöyle yaparız
javac -cp ./core-java/target/classes
-Xplugin:plugin
./core-java/src/main/java/com/JavaTutorials/javac/sampleClass.java Hi from plugin
TaskListener Arayüzü
Şu satırı dahil ederiz
import com.sun.source.util.JavacTask;
com.sun.source.util.JavacTask nesnesine listener takılabilir
Örnek
Şöyle yaparız
public void init(JavacTask task, String... args) {
task.addTaskListener(new TaskListener() {
@Override
public void started(TaskEvent e) {
}
@Override
public void finished(TaskEvent e) {
if (e.getKind() != TaskEvent.Kind.PARSE) {
return;
}
// Perform instructions
}
});
}
finished metodu
TaskEvent nesnesinin getKind() metodu şunları döndürebilir
PARSE - builds an Abstract Syntax Tree (AST)ENTER - source code imports are resolvedANALYZE - We analyze parser output for errorsGENERATE - Creating binaries for the target source fileThere are two more event kinds - ANNOTATION_PROCESSING and ANNOTATION_PROCESSING_ROUND but we don’t bother about them here.
Örnek - Extract AST Data
Şöyle yaparız. com.sun.source.util.TreeScanner kullanılıyor TreeScanner sınıfı com.sun.source.tree.TreeVisitor arayüzünü gerçekleştirir
public void finished(TaskEvent e) {
if (e.getKind() != TaskEvent.Kind.PARSE) {
return;
}
e.getCompilationUnit().accept(new TreeScanner<Void, Void>() {
@Override
public Void visitClass(ClassTree currentNode, Void aVoid) {
return super.visitClass(currentNode, aVoid);
}
@Override
public Void visitMethod(MethodTree currentNode, Void aVoid) {
return super.visitMethod(currentNode, aVoid);
}
}, null);
}
Örnek - Modify AST Data
Şöyle yaparız. Burada amaç @Position olarak benim tanımladığım bir anotasyon için kod üretip geçilen parametre eksi bir değerse exception fırlatmak
public void finished(TaskEvent e) {
if (e.getKind() != TaskEvent.Kind.PARSE) {
return;
}
e.getCompilationUnit().accept(
new TreeScanner<Void, Void>() {
@Override
public Void visitMethod(MethodTree method, Void v) {
List<VariableTree> parametersToInstrument
= method.getParameters().stream()
.filter(SampleJavacPlugin.this::shouldInstrument)
.collect(Collectors.toList());
if (!parametersToInstrument.isEmpty()) {
Collections.reverse(parametersToInstrument);
parametersToInstrument.forEach(p -> addCheck(method, p, context));
}
return super.visitMethod(method, v);
} // visitMethod
}, null); //accept
}
private static Set<String> TARGET_TYPES = Stream.of(
byte.class, short.class, char.class,
int.class, long.class, float.class, double.class)
.map(Class::getName)
.collect(Collectors.toSet());
private boolean shouldInstrument(VariableTree parameter) {
return TARGET_TYPES.contains(parameter.getType().toString())
&& parameter.getModifiers().getAnnotations().stream()
.anyMatch(a -> Positive.class.getSimpleName()
.equals(a.getAnnotationType().toString()));
}
addCheck metodu AST'yi değiştiren yer. Şöyle yaparız. Bu kodu tam olarak kopyalamadım.
private void addCheck(MethodTree myMethod, VariableTree myParameter, Context myContext) {
JCTree.JCIf check = createCheck(myParameter, myContext);
JCTree.JCBlock body = (JCTree.JCBlock) myMethod.getBody();
body.stats = body.stats.prepend(check);
}
private static JCTree.JCIf createCheck(VariableTree parameter, Context context) {
TreeMaker factory = TreeMaker.instance(context);
Names symbolsTable = Names.instance(context);
return factory.at(((JCTree) parameter).pos)
.If(factory.Parens(
createIfCondition(factory, symbolsTable, parameter)),
createIfBlock(factory, symbolsTable, parameter),
null)
}
Hiç yorum yok:
Yorum Gönder